﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Blank.Http;
using Blank.Http.Enumrator;
using System.Net;
using System.Web;
using System.Drawing;
using System.IO;
using Demo.Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Blank.Extends;

namespace Demo.Site
{
    public class MiSite : ISite
    {
        private LoginState _LoginState = LoginState.登出;
        public string UserName { get; set; }
        public string Password { get; set; }
        public MLoginResult LoginResult { get; set; }
        public LoginState LoginState
        {
            get { return _LoginState; }
            set { _LoginState = value; }
        }
        public string BtnText
        {
            get
            {
                if (LoginState == LoginState.已登录)
                    return "注销";
                else
                    return "登录";
            }
        }
        private string InitialAddress = string.Empty;
        public event EventHandler LoginCompleted;

        public MiSite()
        {
            base.Host = "order.xiaomi.com";
            base.MyWebAddress = "http://order.xiaomi.com/site/login?ac=1";
            this.InitialAddress = "http://order.xiaomi.com/site/login?ac=1";
            base.AllowAutoRedirect = true;
            base.InputValidateCodeCompleted += new EventHandler<Blank.Http.EventArg.InputValidateCodeEventArgs>(MiSite_InputValidateCodeCompleted);
        }

        private void MiSite_InputValidateCodeCompleted(object sender, Blank.Http.EventArg.InputValidateCodeEventArgs e)
        {
            e.ValidateCode = InputValidateCodeForm.Show(e.ValidateCodeImage);
        }


        public void Login()
        {
            try
            {
                InitialLoginPage();
            }
            catch (Exception ex)
            {
                base.ShowErrorMessage(ex);
            }
        }


        private void InitialLoginPage()
        {
            HttpWebRequest request = base.CreateGetRequest("{0}");
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0";
            request.Accept = "text/html,application/xhtml+xml,application/xml";
            request.Headers.Add("Accept-Language", "zh-cn,zh");
            request.Headers.Add("Accept-Encoding", "gzip,deflate");
            try
            {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    base.Cookie.Add(response.Cookies);
                    string url = PrepareLoginPageUrl(response);
                    this.DoLogin(url, request.RequestUri.AbsoluteUri);
                }
            }
            catch (Exception ex)
            {
                base.ShowErrorMessage(ex);
            }
            finally
            {
                request.Abort();
            }
        }
        /// <summary>
        /// 开始登录
        /// </summary>
        /// <param name="url"></param>
        private void DoLogin(string url, string referer)
        {
            HttpWebRequest request = base.CreateGetRequest(string.Format("https://account.xiaomi.com{0}", url));
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0";
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.CookieContainer = this.Cookie;
            request.Headers.Add("Accept-Language", "zh-cn,zh");
            request.Headers.Add("Accept-Encoding", "gzip,deflate");
            request.Referer = referer;
            try
            {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    base.Cookie.Add(response.Cookies);
                    string postData = PreparePostData(response, referer);
                    BeginLogin(postData, referer);
                }
            }
            catch (Exception ex)
            {
                base.ShowErrorMessage(ex);
            }
            finally
            {
                request.Abort();
            }
        }

        private void BeginLogin(string postData, string referer)
        {
            byte[] bytes = base.Encoding.GetBytes(postData);
            HttpWebRequest request = base.CreatePostRequest("https://account.xiaomi.com/pass/serviceLoginAuth2");
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0";
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.CookieContainer = this.Cookie;
            request.Headers.Add("Accept-Language", "zh-cn,zh");
            request.Headers.Add("Accept-Encoding", "gzip,deflate");
            request.Referer = referer;
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = bytes.Length;
            using (Stream stream = request.GetRequestStream())
            {
                stream.Write(bytes, 0, bytes.Length);
            }
            request.BeginGetResponse(EndLogin);
        }

        private void EndLogin(HttpWebResponse response)
        {
            try
            {
                using (response)
                {
                    base.Cookie.Add(response.Cookies);
                    string html = response.ReadString(base.Encoding);
                    html = string.Concat(html.Replace("&&&START&&&", ""), "}");
                    this.LoginResult = html.JsonToObject<MLoginResult>();
                    if (this.LoginCompleted != null)
                        this.LoginCompleted(this, EventArgs.Empty);
                    base.ShowNormalMessage("登陆 {0}", this.LoginResult.desc);
                }
            }
            catch (Exception ex)
            {
                base.ShowErrorMessage(ex);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private string PrepareLoginPageUrl(HttpWebResponse response)
        {
            Encoding encoding = base.Encoding;
            string html = response.ReadString(ref encoding);
            base.Encoding = encoding;
            var callback = html.GetRegValue("var callback = encodeURIComponent\\(\"(?<BUHUO>.*?)\"\\);");
            var sid = html.GetRegValue("var sid = encodeURIComponent\\(\"(?<BUHUO>.*?)\"\\);");
            var qs = html.GetRegValue("var qs = encodeURIComponent\\(\"(?<BUHUO>.*?)\"\\);");
            var hidden = html.GetRegValue("var hidden = encodeURIComponent\\(\"(?<BUHUO>.*?)?\"\\);");
            var sign = html.GetRegValue("var sign = encodeURIComponent\\(\"(?<BUHUO>.*?)\"\\);");
            var _customDisplay = string.IsNullOrEmpty(response.GetParam("_customDisplay")) ? "0" : response.GetParam("_customDisplay");

            callback = HttpUtility.UrlEncode(callback);
            sid = HttpUtility.UrlEncode(sid);
            qs = HttpUtility.UrlEncode(qs);
            hidden = HttpUtility.UrlEncode(hidden);
            sign = HttpUtility.UrlEncode(sign);
            _customDisplay = HttpUtility.UrlEncode(_customDisplay);
            var _dc = JavascriptExtends.GetTime();

            string url = response.ResponseUri.AbsoluteUri;
            while (url.Contains("%"))
            {
                url = HttpUtility.UrlDecode(url, base.Encoding);
            }
            var hide_third = response.GetParam("hide_third");
            var cookieLocale = response.GetCookie("uLocale");

            StringBuilder iframeSrc = new StringBuilder();
            if (response.ResponseUri.Host.IndexOf("onebox") > -1)
                iframeSrc.Append("/pass/static/v5login_onebox.html?inframe=true&onetimeEncode=true");
            else
                iframeSrc.Append("/pass/static/v5login.html?inframe=true&onetimeEncode=true");
            if ("true".Equals(hide_third))
                iframeSrc.Append("&hide_third=true");

            var matched = url.GetRegValueMatches("/\b(_locale=en)|(_locale=zh_TW)|(_locale=zh_CN)\b/");
            if (!string.IsNullOrEmpty(cookieLocale) && matched.Count == 0)
                iframeSrc.Append("&_locale=" + cookieLocale);

            iframeSrc.Append("&callback=" + callback);
            iframeSrc.Append("&sid=" + sid);
            iframeSrc.Append("&qs=" + qs);
            iframeSrc.Append("&sign=" + sign);
            iframeSrc.Append("&hidden=" + hidden);
            iframeSrc.Append("&_customDisplay=" + _customDisplay);
            iframeSrc.Append("&_dc=" + _dc);
            return iframeSrc.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <param name="referer"></param>
        /// <returns></returns>
        private string PreparePostData(HttpWebResponse response, string referer)
        {
            StringBuilder postStr = new StringBuilder();
            string html = response.ReadString(base.Encoding);
            Dictionary<string, object> postData = new Dictionary<string, object>
                    {
                        {"user",HttpUtility.UrlDecode(this.UserName)},
                        {"_json",true}
                    };
            if (string.IsNullOrEmpty(this.Password) == false)
                postData.Add("pwd", HttpUtility.UrlDecode(this.Password));
            this.PrepareDataAttribute(response, "sid", "sid", ref postData);
            this.PrepareDataAttribute(response, "sign", "_sign", ref postData);
            this.PrepareDataAttribute(response, "callback", "callback", ref postData);
            this.PrepareDataAttribute(response, "qs", "qs", ref postData);
            this.PrepareDataAttribute(response, "hidden", "hidden", ref postData);
            this.PrepareDataAttribute(response, "redirectTarget", "redirectTarget", ref postData);
            postData.Add("auto", true);
            string validataCode = html.GetRegValue("id=\"img_code_area\" style=\"display:(?<BUHUO>.*?);\"");
            if ("block".Equals(validataCode))
            {
                ReadValidataCode(html, referer, ref validataCode);
                postData.Add("captCode", true);
            }

            foreach (string key in postData.Keys)
            {
                postStr.AppendFormat("&{0}={1}", key, postData[key]);
            }

            return postStr.Remove(0, 1).ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="html"></param>
        /// <param name="referer"></param>
        /// <param name="validataCode"></param>
        private void ReadValidataCode(string html, string referer, ref string validataCode)
        {
            string imgUrl = html.GetRegValue("src=\"(?<BUHUO>.*?)\" class=\"code-img\"");
            HttpWebRequest _request = base.CreateGetRequest(string.Format("https://account.xiaomi.com{0}", imgUrl));
            _request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0";
            _request.Accept = "text/html, application/xhtml+xml, */*";
            _request.CookieContainer = this.Cookie;
            _request.Headers.Add("Accept-Language", "zh-cn,zh");
            _request.Headers.Add("Accept-Encoding", "gzip,deflate");
            _request.Referer = referer;
            try
            {
                using (HttpWebResponse _response = (HttpWebResponse)_request.GetResponse())
                {
                    Image image = _response.ReadImage();
                    base.OnInputValidateCode(new Blank.Http.EventArg.InputValidateCodeEventArgs(image, validataCode));
                }
            }
            catch (Exception ex)
            {

            }
            finally
            {
                _request.Abort();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <param name="paramName"></param>
        /// <param name="attributeName"></param>
        /// <param name="data"></param>
        private void PrepareDataAttribute(HttpWebResponse response, string paramName, string attributeName, ref Dictionary<string, object> data)
        {
            var paramValue = response.GetParam(paramName);
            if (string.IsNullOrEmpty(paramValue) == false)
            {
                if (!data.ContainsKey(attributeName))
                    data.Add(attributeName, null);
                if ("true".Equals(response.GetParam("onetimeEncode")))
                {
                    data[attributeName] = paramValue;
                }
                else
                {
                    data[attributeName] = HttpUtility.UrlDecode(paramValue);
                }
            }
        }



    }

}
